﻿using System.IO;
using System.Linq;
using NAnt.Core;
using NAnt.Core.Attributes;

namespace Lean.NantTasks.Deployment
{
    /// <summary>
    /// In case you deploy to a certain location using a revision-number in the directories name
    /// this tasks get in handy to remove old revisions.
    /// Basically it scans a given path for all folders with a given prefix. It then removes the prefix and attempts to parse the rest as int.
    /// In the end this tasks deletes the oldest (the owns with the smallest number) leaving just a given number of backups.
    /// </summary>
    [TaskName("deleteoldfolders")]
    public class DeleteOldFolders : Task 
    {
        [TaskAttribute("path"), StringValidator(AllowEmpty = false)]
        public string BasePath { get; set; }

        [TaskAttribute("prefix"), StringValidator(AllowEmpty = false)]
        public string Prefix { get; set; }

        [TaskAttribute("backups"), StringValidator(AllowEmpty = false)]
        public int NumberOfBackups { get; set; }

        protected override void ExecuteTask()
        {
            try
            {
                DeleteFolders(new DirectoryInfo(BasePath), Prefix, NumberOfBackups);
            }
            catch
            {
                if (FailOnError)
                    throw;
            }
        }

        public void DeleteFolders(DirectoryInfo dirinfo, string prefix, int numberOfBackups)
        {
            var possibleDirs = dirinfo.GetDirectories(prefix + "*", SearchOption.TopDirectoryOnly);

            var orderedDirs = possibleDirs
                                    .OfType<DirectoryInfo>()
                                    .Where(dir => DirNameContainsNumber(dir, prefix))
                                    .OrderByDescending( dir => DirNameToNum(dir, prefix))
                                    .Skip(numberOfBackups);

            foreach (var dir in orderedDirs) {
                Log(Level.Info, "Deleting "+ dir.FullName);
                dir.Delete(true);
            }
        }

        private bool DirNameContainsNumber(DirectoryInfo dir, string prefix)
        {
            var fullName = Path.Combine(dir.Parent.FullName, prefix);
            var subName = dir.FullName.Substring(fullName.Length);
            
            int res;
            return int.TryParse(subName, out res);
        }

        private int DirNameToNum(DirectoryInfo dir, string prefix)
        {
            var fullName = Path.Combine(dir.Parent.FullName, prefix);
            var subName = dir.FullName.Substring(fullName.Length);
            return int.Parse(subName);
        }
    }
}
